package java_thinking.unit_15._15_8;

/**
 * @Description :   创建类型(泛型)实例  工厂设计模式
 *                  java中解决方案就是传递一个工厂对象，并使用它来创建新的实例，
 *                  最便利的工厂对象就是class对象，因此使用类型标签，就可以使用newInstance()来
 *                  创建这个类型的新对象
 *
 *                  重要的案例！！！
 * @author: cww
 * @DateTime: 2019-04-04 23:17
 */

/**
 * 普通泛型工厂，缺点，没有编译检查
 * @param <T>
 */
class ClassAsFactory<T> {
    T x;
    public ClassAsFactory(Class<T> kind) {
        try {
            x = kind.newInstance();
        } catch (Exception e) {
            throw new RuntimeException();
        }
    }
}
class Employee {}
/**
 * @author asd730520@live.com
 */
public class InstantiateGenericType {
    public static void main(String[] args) {
        ClassAsFactory<Employee> fr = new ClassAsFactory<>(Employee.class);
        System.out.println("ClassAsFactory<Employee> ok");
        /**
         * 当使用Integer时会报错，因为Integer没有任何默认的无参构造器，
         * 因为这个错误不是在编译器捕获的，所以，建议使用显式的工厂，
         * 并将限制其类型，使得只能接受实现了这个工厂的类
         */
        ClassAsFactory<Integer> fi = new ClassAsFactory<>(Integer.class);
    }
}

/**
 * ******************************************************************************
 * @param <T>
 */
interface FactoryI<T> {
    T create(int i);
}

class Foo2<T> {
    public T x;

    /**
     * 这是带泛型的构造方法，别看错了
     * @param factory
     * @param <F>
     */
    public <F extends FactoryI<T>> Foo2(F factory) {
        /**
         * 这里随意传入一个允许的参数即可
         */
        x = factory.create(1);
    }
}

/**
 *
 * 显式的工厂对象，获得了编译期检查
 * 这种方法是上面直接传递Class<T>的一种变体，两种方式都传递了工厂对象
 */
class IntegerFactory implements FactoryI<Integer> {

    @Override
    public Integer create(int i) {
        return new Integer(i);
    }
}

class Wigdet {
    private final int i ;
    Wigdet(int i) {
        this.i = i;
    }
    public static class Factory implements FactoryI<Wigdet> {
        @Override
        public Wigdet create(int i) {
            return new Wigdet(i);
        }
    }
}

class FactoryConstraint {
    public static void main(String[] args) {
        Foo2<Integer>  p  = new Foo2<>(new IntegerFactory());
        System.out.println(p.x);
        Foo2<Wigdet> integer1 =  new Foo2<Wigdet>(new Wigdet.Factory());
        IntegerFactory integerFactory = new IntegerFactory();
        Integer integer  = integerFactory.create(5);
    }
}

/**
 * 模板设计模式
 * @param <T>
 */
abstract class GenericWithCreate<T> {
    final T element;
    GenericWithCreate() {
        element = create();
    }
    abstract T create();
}
class X {
    public X(String in) {
        System.out.println(in);
    }
}
class Creator extends GenericWithCreate<X> {
    @Override
    X create() {
        return new X("in");
    }
    void f(){
        System.out.println(element.getClass().getSimpleName());
    }
}
class IntegerCreate extends GenericWithCreate<Integer> {

    @Override
    Integer create() {
        return new Integer(0);
    }
}
class CreatorGeneric {
    public static void main(String[] args) {
        Creator c = new Creator();
        c.f();
        X x = c.create();
    }
}


//模板设计模式
abstract class GenericModel1<T> {
    final T element;
    public GenericModel1() {
        element = create();
    }
    abstract T create();
}

class BusiClass1 {
    private int i;
    public BusiClass1(int i) {
        this.i = i;
    }
}

class CreateBusiClass extends GenericModel1<BusiClass1> {

    @Override
    BusiClass1 create() {
        return new BusiClass1(3);
    }
}

class TestGeneric {
    public static void main(String[] args) {
        CreateBusiClass createBusiClass = new CreateBusiClass();
        createBusiClass.create();
    }
}